package cn.doitedu.crawler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BilibiliVideo {

    public static void main(String[] args) throws IOException, InterruptedException {

        // 构建httpclient客户端
        CloseableHttpClient client = HttpClientBuilder.create()
                .setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36")
                .build();


        // 构建get请求参数
        HttpGet httpGet = new HttpGet("https://www.bilibili.com/video/BV1Bo4y1A7TM/");
        httpGet.setHeader("referer","https://www.bilibili.com/video/BV1Bo4y1A7TM?spm_id_from=333.337.search-card.all.click");

        // 执行请求
        CloseableHttpResponse response = client.execute(httpGet);

        // 获取响应体(页面HTML)并转成字符串
        String s = EntityUtils.toString(response.getEntity());

        // 用正则抽取标题
        Pattern titlePattern = Pattern.compile("<h1 title=\"(.*?)\" class=");
        Matcher titleMatcher = titlePattern.matcher(s);
        String title = "";
        while(titleMatcher.find()){
            title = titleMatcher.group(1);
        }


        // 音频、视频地址等信息所在的json数据，在页面 html的如下位置：<script>window.__playinfo__=
        // 直接用正则从页面html中抽取
        Pattern pattern = Pattern.compile("<script>window\\.__playinfo__=(.*?)</script>");
        Matcher matcher = pattern.matcher(s);
        String json = "";
        while(matcher.find()){
            json = matcher.group(1);
        }

        // 如果没有抽取到，则直接退出
        if(json.equals("")){
            System.out.println("音视频地址信息抽取失败，退出");
            System.exit(1);
        }

        // 解析json
        JSONObject jsonObject = JSON.parseObject(json);

        // 音频地址取数路径：json_data['data']['dash']['audio'][0]['backupUrl'][0]
        String audioUrl = jsonObject.getJSONObject("data").getJSONObject("dash").getJSONArray("audio").getJSONObject(0).getJSONArray("backupUrl").getString(0);
        // 视频地址取数路径：json_data['data']['dash']['video'][0]['backupUrl'][0]
        String videoUrl = jsonObject.getJSONObject("data").getJSONObject("dash").getJSONArray("video").getJSONObject(0).getJSONArray("backupUrl").getString(0);

        // 根据地址请求视频数据，并写入本地文件
        HttpGet videoGet = new HttpGet(videoUrl);
        videoGet.setHeader("referer","https://www.bilibili.com/video/BV1Bo4y1A7TM?spm_id_from=333.337.search-card.all.click");
        CloseableHttpResponse videoResponse = client.execute(videoGet);
        InputStream content = videoResponse.getEntity().getContent();
        FileOutputStream mp4FileOutputStream = new FileOutputStream(String.format("d:/%s.mp4",title));
        IOUtils.copy(content,mp4FileOutputStream);


        // 根据地址请求音频数据，并写入本地文件
        HttpGet audioGet = new HttpGet(audioUrl);
        audioGet.setHeader("referer","https://www.bilibili.com/video/BV1Bo4y1A7TM?spm_id_from=333.337.search-card.all.click");
        CloseableHttpResponse audioResponse = client.execute(audioGet);
        InputStream audioContent = audioResponse.getEntity().getContent();

        FileOutputStream mp3FileOutputStream = new FileOutputStream(String.format("d:/%s.mp3",title));
        IOUtils.copy(audioContent,mp3FileOutputStream);

        // 关闭本地文件流
        IOUtils.closeQuietly(mp4FileOutputStream);
        IOUtils.closeQuietly(mp3FileOutputStream);

        // 调用ffmpeg，将音视频合并
        //String title = "杨天真：认清人脉本质，打破向上社交的恐惧";
        String cmd = String.format("D:/devapps/ffmpeg/bin/ffmpeg.exe -i d:/%s.mp4 -i d:/%s.mp3 -vcodec copy -acodec copy d:/%s.mp4", title, title, title + "-ok");
        System.out.println(cmd);
        try {
            Process exec = Runtime.getRuntime().exec(cmd);

            InputStream errorStream = exec.getErrorStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(errorStream));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }

            // 删除原始mp4和mp3文件
            new File(String.format("d:/%s.mp4", title)).delete();
            new File(String.format("d:/%s.mp3", title)).delete();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }


}
